// Redis客户端核心类

import Redis, { Cluster } from 'ioredis';
import {
  RedisConfig,
  ClusterConfig,
  Logger,
  HealthStatus,
  ConnectionStats,
  Middleware,
  Operation,
} from '../types';
import { defaultLogger } from '../utils/logger';
import { smartSerialize, smartDeserialize } from '../utils/serializer';

export class RedisClient {
  private client!: Redis | Cluster;
  private config: RedisConfig | ClusterConfig;
  private logger: Logger;
  private middlewares: Middleware[] = [];
  private isCluster: boolean;
  private connectionStartTime: number;
  private operationCount = 0;
  private totalResponseTime = 0;

  constructor(config: RedisConfig | ClusterConfig) {
    this.config = config;
    this.logger = config.logger ?? defaultLogger.createChild('RedisClient');
    this.isCluster = 'nodes' in config;
    this.connectionStartTime = Date.now();

    this.initializeClient();
  }

  /**
   * 初始化Redis客户端
   */
  private initializeClient(): void {
    try {
      if (this.isCluster) {
        const clusterConfig = this.config as ClusterConfig;
        this.client = new Cluster(clusterConfig.nodes, {
          enableReadyCheck: clusterConfig.enableReadyCheck ?? true,
          maxRetriesPerRequest: clusterConfig.maxRetriesPerRequest ?? 3,
          ...this.getBaseOptions(),
        });
      } else {
        this.client = new Redis({
          ...this.config,
          ...this.getBaseOptions(),
        });
      }

      this.setupEventHandlers();
      this.logger.info('Redis client initialized successfully');
    } catch (error) {
      this.logger.error('Failed to initialize Redis client', { error });
      throw error;
    }
  }

  /**
   * 获取基础配置选项
   */
  private getBaseOptions(): any {
    return {
      retryDelayOnFailover: this.config.retryDelay ?? 100,
      maxRetriesPerRequest: this.config.retryAttempts ?? 3,
      connectTimeout: this.config.connectionTimeout ?? 10000,
      lazyConnect: true,
      keyPrefix: this.config.keyPrefix ?? '',
    };
  }

  /**
   * 设置事件处理器
   */
  private setupEventHandlers(): void {
    this.client.on('connect', () => {
      this.logger.info('Connected to Redis');
    });

    this.client.on('ready', () => {
      this.logger.info('Redis client ready');
    });

    this.client.on('error', error => {
      this.logger.error('Redis client error', { error });
    });

    this.client.on('close', () => {
      this.logger.warn('Redis connection closed');
    });

    this.client.on('reconnecting', () => {
      this.logger.info('Reconnecting to Redis');
    });
  }

  /**
   * 连接到Redis
   */
  async connect(): Promise<void> {
    try {
      await this.client.connect();
      this.logger.info('Successfully connected to Redis');
    } catch (error) {
      this.logger.error('Failed to connect to Redis', { error });
      throw error;
    }
  }

  /**
   * 断开连接
   */
  async disconnect(): Promise<void> {
    try {
      this.client.disconnect();
      this.logger.info('Disconnected from Redis');
    } catch (error) {
      this.logger.error('Error during disconnect', { error });
      throw error;
    }
  }

  /**
   * 获取原始Redis客户端
   */
  getClient(): Redis | Cluster {
    return this.client;
  }

  /**
   * 添加中间件
   */
  use(middleware: Middleware): void {
    this.middlewares.push(middleware);
  }

  /**
   * 执行Redis命令
   */
  async execute<T = any>(command: string, ...args: any[]): Promise<T> {
    const operation: Operation = {
      command,
      args,
      key: args[0],
      timestamp: Date.now(),
    };

    const startTime = Date.now();

    try {
      // 执行前置中间件
      for (const middleware of this.middlewares) {
        if (middleware.before) {
          await middleware.before(operation);
        }
      }

      // 执行Redis命令
      const result = await (this.client as any)[command](...args);

      // 记录性能指标
      const duration = Date.now() - startTime;
      operation.duration = duration;
      this.operationCount++;
      this.totalResponseTime += duration;

      // 执行后置中间件
      for (const middleware of this.middlewares) {
        if (middleware.after) {
          await middleware.after(operation, result);
        }
      }

      return result;
    } catch (error) {
      const duration = Date.now() - startTime;
      operation.duration = duration;

      // 执行错误中间件
      for (const middleware of this.middlewares) {
        if (middleware.error) {
          await middleware.error(operation, error as Error);
        }
      }

      this.logger.error(`Redis command failed: ${command}`, {
        args,
        error,
        duration,
      });
      throw error;
    }
  }

  /**
   * 设置值
   */
  async set(key: string, value: any, ttl?: number): Promise<void> {
    const serializedValue = this.config.autoSerialize !== false ? smartSerialize(value) : value;

    if (ttl) {
      await this.execute('setex', key, ttl, serializedValue);
    } else {
      await this.execute('set', key, serializedValue);
    }
  }

  /**
   * 获取值
   */
  async get<T = any>(key: string): Promise<T | null> {
    const value = await this.execute<string | null>('get', key);

    if (value === null) {
      return null;
    }

    return this.config.autoSerialize !== false ? smartDeserialize<T>(value) : (value as T);
  }

  /**
   * 删除键
   */
  async del(...keys: string[]): Promise<number> {
    return this.execute<number>('del', ...keys);
  }

  /**
   * 检查键是否存在
   */
  async exists(...keys: string[]): Promise<number> {
    return this.execute<number>('exists', ...keys);
  }

  /**
   * 设置过期时间
   */
  async expire(key: string, seconds: number): Promise<number> {
    return this.execute<number>('expire', key, seconds);
  }

  /**
   * 获取TTL
   */
  async ttl(key: string): Promise<number> {
    return this.execute<number>('ttl', key);
  }

  /**
   * 获取所有匹配的键
   */
  async keys(pattern: string): Promise<string[]> {
    return this.execute<string[]>('keys', pattern);
  }

  /**
   * 管道操作
   */
  pipeline(): any {
    return this.client.pipeline();
  }

  /**
   * 事务操作
   */
  multi(): any {
    return this.client.multi();
  }

  /**
   * 健康检查
   */
  async healthCheck(): Promise<HealthStatus> {
    try {
      await this.execute('ping');

      const info = await this.execute<string>('info', 'memory');
      const memoryInfo = this.parseInfo(info);

      return {
        status: 'healthy',
        uptime: Date.now() - this.connectionStartTime,
        connections: {
          active: 1, // 简化实现
          total: 1,
        },
        memory: {
          used: parseInt(memoryInfo['used_memory'] ?? '0'),
          peak: parseInt(memoryInfo['used_memory_peak'] ?? '0'),
        },
        lastCheck: new Date(),
      };
    } catch (error) {
      return {
        status: 'unhealthy',
        uptime: Date.now() - this.connectionStartTime,
        connections: { active: 0, total: 0 },
        memory: { used: 0, peak: 0 },
        lastCheck: new Date(),
      };
    }
  }

  /**
   * 获取连接统计
   */
  getConnectionStats(): ConnectionStats {
    return {
      totalConnections: 1,
      activeConnections: this.client.status === 'ready' ? 1 : 0,
      idleConnections: 0,
      failedConnections: 0,
      averageResponseTime:
        this.operationCount > 0 ? this.totalResponseTime / this.operationCount : 0,
    };
  }

  /**
   * 解析Redis INFO命令输出
   */
  private parseInfo(info: string): Record<string, string> {
    const result: Record<string, string> = {};
    const lines = info.split('\r\n');

    for (const line of lines) {
      if (line.includes(':')) {
        const [key, value] = line.split(':');
        if (key && value !== undefined) {
          result[key] = value;
        }
      }
    }

    return result;
  }
}
